/**
 * Copyright 2019-2020 Huawei Technologies Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <gtest/gtest.h>



#define protected public
#define private public
#include "graph_optimizer/fe_graph_optimizer.h"
#include "graph/utils/graph_utils.h"
#include "graph/utils/op_desc_utils.h"
#include "common/configuration.h"
#include "graph/ge_tensor.h"
#include "graph/op_desc.h"
#include "graph/compute_graph.h"
#include "graph/utils/attr_utils.h"
#include "graph/utils/tensor_utils.h"
// #include "all_ops.h"
#include "array_ops.h"
#include "selection_ops.h"
#include "matrix_calculation_ops.h"
#include "elewise_calculation_ops.h"
#include "reduce_ops.h"
#include "common/util/op_info_util.h"
#include "adapter/tbe_adapter/tbe_op_store_adapter.h"
#include <graph_optimizer/fe_graph_optimizer.h>
#include "ops_kernel_store/fe_ops_kernel_info_store.h"
#include "ops_store/ops_kernel_manager.h"
#include <fusion_rule_manager/fusion_rule_data/fusion_rule_pattern.h>
#include "graph_optimizer/graph_fusion/graph_replace.h"
#undef protected
#undef private

using namespace testing;
using namespace ge;
using namespace fe;

class STEST_fusion_engine_fe_graph_optimizer : public testing::Test {
protected:
  FEOpsKernelInfoStorePtr ops_info_store;
  OpStoreAdapterManagerPtr op_store_adapter_manager_ptr_;
  std::vector<FEOpsStoreInfo> cfg_info_;
  ConcatOptimizer concat_optimizer;
  RefRelationsPtr reflection_builder_ptr_;
  void SetUp() {
    reflection_builder_ptr_ = std::make_shared<ge::RefRelations>();
    op_store_adapter_manager_ptr_ = std::make_shared<OpStoreAdapterManager>();
    ops_info_store = std::make_shared<FEOpsKernelInfoStore>(op_store_adapter_manager_ptr_);
    FEOpsStoreInfo TIK_CUSTOM_OPINFO_STUB = {
            1,
            "tik-custom",
            EN_IMPL_CUSTOM_TIK,
            "./air/test/engines/nneng/st/stub/fe_config/tik_custom_opinfo",
            ""
    };
    FEOpsStoreInfo TBE_CUSTOM_OPINFO_STUB = {
            2,
            "tbe-custom",
            EN_IMPL_CUSTOM_TBE,
            "./air/test/engines/nneng/st/stub/fe_config/tbe_custom_opinfo",
            ""
    };
    FEOpsStoreInfo TIK_OPINFO_STUB = {
            5,
            "tik-builtin",
            EN_IMPL_HW_TIK,
            "./air/test/engines/nneng/st/stub/fe_config/tik_opinfo",
            ""
    };
    FEOpsStoreInfo TBE_OPINFO_STUB = {
            6,
            "tbe-builtin",
            EN_IMPL_HW_TBE,
            "./air/test/engines/nneng/st/stub/fe_config/tbe_opinfo",
            ""
    };
    FEOpsStoreInfo RL_OPINFO_STUB = {
            7,
            "rl-built",
            EN_IMPL_RL,
            "./air/test/engines/nneng/st/stub/fe_config/rl_opinfo",
            ""
    };

    cfg_info_.push_back(TIK_CUSTOM_OPINFO_STUB);
    cfg_info_.push_back(TBE_CUSTOM_OPINFO_STUB);
    cfg_info_.push_back(TIK_OPINFO_STUB);
    cfg_info_.push_back(TBE_OPINFO_STUB);
    cfg_info_.push_back(RL_OPINFO_STUB);
  }

  void TearDown() {

  }

  static void CreateComplexGraph(ComputeGraphPtr graph, string data_type) {
    shared_ptr<ge::OpDesc> op_desc_ptr = make_shared<ge::OpDesc>("tbe_conv2d", "Convolution");

    vector<ge::GeTensorPtr> weights;
    vector<int64_t> dim_weight = {256, 256, 512};
    uint32_t data_size = 256 * 256 * 512;
    GeShape shape_weight(dim_weight);
    GeTensorDesc weight_desc(shape_weight);
    GeTensor tensor(weight_desc);
    if (data_type == "float") {
      weight_desc.SetDataType(DT_FLOAT);
      vector<float> weight(data_size, 0.01);
      vector<uint8_t> buffer(data_size * 4);
      memcpy(buffer.data(), weight.data(), data_size * 4);
      tensor.SetData(std::move(buffer));
    } else if (data_type == "int32") {
      weight_desc.SetDataType(DT_INT32);
      vector<int32_t> weight(data_size, 1);
      vector<uint8_t> buffer(data_size * 4);
      memcpy(buffer.data(), weight.data(), data_size * 4);
      tensor.SetData(std::move(buffer));
    }
    GeTensorPtr tensor_ptr = make_shared<GeTensor>(tensor);
    weights.emplace_back(tensor_ptr);

    OpDescPtr weight_op_desc1 = std::make_shared<OpDesc>("w1", "Const");
    weight_op_desc1->AddInputDesc("x", weight_desc);
    weight_op_desc1->AddOutputDesc("z", weight_desc);
    std::vector<bool> w_input_const;
    w_input_const.emplace_back(false);
    weight_op_desc1->SetIsInputConst(w_input_const);

    int64_t int_value = 1;
    float float_value = 2.0;
    bool bool_value = false;
    string str_value = "abc";
    vector<int64_t> int_vec{1, 2, 3};
    vector<int64_t> rint_vec;
    vector<float> float_vec{4.0, 5.0, 6.0};
    vector<float> rfloat_vec;
    vector<bool> bool_vec{false, true, true};
    vector<bool> rbool_vec;
    std::vector<string> str_vec{"a", "b", "c"};
    AttrUtils::SetInt(op_desc_ptr, "transposX", int_value);
    AttrUtils::SetFloat(op_desc_ptr, "transposY", float_value);
    AttrUtils::SetBool(op_desc_ptr, "attrBool", bool_value);
    AttrUtils::SetStr(op_desc_ptr, "attrStr", str_value);
    AttrUtils::SetListInt(op_desc_ptr, "attrListInt", int_vec);
    AttrUtils::SetListFloat(op_desc_ptr, "attrListFloat", float_vec);
    AttrUtils::SetListBool(op_desc_ptr, "attrListBool", bool_vec);
    AttrUtils::SetListStr(op_desc_ptr, "attrListStr", str_vec);

    AttrUtils::SetInt(weight_op_desc1, "transposX", int_value);
    AttrUtils::SetFloat(weight_op_desc1, "transposY", float_value);
    AttrUtils::SetBool(weight_op_desc1, "attrBool", bool_value);
    AttrUtils::SetStr(weight_op_desc1, "attrStr", str_value);
    AttrUtils::SetListInt(weight_op_desc1, "attrListInt", int_vec);
    AttrUtils::SetListFloat(weight_op_desc1, "attrListFloat", float_vec);
    AttrUtils::SetListBool(weight_op_desc1, "attrListBool", bool_vec);
    AttrUtils::SetListStr(weight_op_desc1, "attrListStr", str_vec);

    ge::DataType set_dtype = ge::DT_FLOAT;
    std::vector<int64_t> shape_vec{256, 256, 512};
    ge::GeShape shape_desc = ge::GeShape(shape_vec);

    shared_ptr<ge::GeTensorDesc> input0_desc_ptr = make_shared<ge::GeTensorDesc>();
    input0_desc_ptr->SetDataType(set_dtype);
    input0_desc_ptr->SetShape(shape_desc);
    op_desc_ptr->AddInputDesc("x", input0_desc_ptr->Clone());

    shared_ptr<ge::GeTensorDesc> input1_desc_ptr = make_shared<ge::GeTensorDesc>();
    if (data_type == "float") {
      input1_desc_ptr->SetDataType(DT_FLOAT);
    } else if (data_type == "int32") {
      input1_desc_ptr->SetDataType(DT_INT32);
    }
    input1_desc_ptr->SetShape(shape_desc);
    op_desc_ptr->AddInputDesc("y", input1_desc_ptr->Clone());

    std::vector<bool> is_input_const;
    is_input_const.emplace_back(false);
    is_input_const.emplace_back(true);
    op_desc_ptr->SetIsInputConst(is_input_const);

    shared_ptr<ge::GeTensorDesc> output_desc_ptr = make_shared<ge::GeTensorDesc>();
    output_desc_ptr->SetDataType(set_dtype);
    output_desc_ptr->SetShape(shape_desc);
    op_desc_ptr->AddOutputDesc("z", output_desc_ptr->Clone());

    AttrUtils::SetInt(op_desc_ptr, "imply_type", EN_IMPL_HW_TBE);
    NodePtr weight_node1 = graph->AddNode(weight_op_desc1);
    NodePtr conv_node = graph->AddNode(op_desc_ptr);
    op_desc_ptr->SetName("conv2");
    NodePtr conv_next_node = graph->AddNode(op_desc_ptr);
    GraphUtils::AddEdge(weight_node1->GetOutDataAnchor(0), conv_node->GetInDataAnchor(1));
    GraphUtils::AddEdge(weight_node1->GetOutDataAnchor(0), conv_next_node->GetInDataAnchor(1));
    GraphUtils::AddEdge(conv_node->GetOutDataAnchor(0), conv_next_node->GetInDataAnchor(0));
    OpDescUtils::SetWeights(*conv_node, weights);
    OpDescUtils::SetWeights(*conv_next_node, weights);
  }

  static void CreateSimpleGraph(ComputeGraphPtr graph) {
    shared_ptr<ge::OpDesc> op_desc_ptr = make_shared<ge::OpDesc>("tbe_conv2d", "conv");

    int64_t int_value = 1;
    float float_value = 2.0;
    bool bool_value = false;
    string str_value = "abc";
    vector<int64_t> int_vec{1, 2, 3};
    vector<int64_t> rint_vec;
    vector<float> float_vec{4.0, 5.0, 6.0};
    vector<float> rfloat_vec;
    vector<bool> bool_vec{false, true, true};
    vector<bool> rbool_vec;
    std::vector<string> str_vec{"a", "b", "c"};
    AttrUtils::SetInt(op_desc_ptr, "transposX", int_value);
    AttrUtils::SetFloat(op_desc_ptr, "transposY", float_value);
    AttrUtils::SetBool(op_desc_ptr, "attrBool", bool_value);
    AttrUtils::SetStr(op_desc_ptr, "attrStr", str_value);
    AttrUtils::SetListInt(op_desc_ptr, "attrListInt", int_vec);
    AttrUtils::SetListFloat(op_desc_ptr, "attrListFloat", float_vec);
    AttrUtils::SetListBool(op_desc_ptr, "attrListBool", bool_vec);
    AttrUtils::SetListStr(op_desc_ptr, "attrListStr", str_vec);

    ge::DataType set_dtype = ge::DT_FLOAT16;
    std::vector<int64_t> shape_vec{256, 256, 512};
    ge::GeShape shape_desc = ge::GeShape(shape_vec);

    shared_ptr<ge::GeTensorDesc> input0_desc_ptr = make_shared<ge::GeTensorDesc>();
    input0_desc_ptr->SetDataType(set_dtype);
    input0_desc_ptr->SetShape(shape_desc);
    op_desc_ptr->AddInputDesc("x", input0_desc_ptr->Clone());

    shared_ptr<ge::GeTensorDesc> input1_desc_ptr = make_shared<ge::GeTensorDesc>();
    input1_desc_ptr->SetDataType(set_dtype);
    input1_desc_ptr->SetShape(shape_desc);
    op_desc_ptr->AddInputDesc("y", input1_desc_ptr->Clone());

    std::vector<bool> is_input_const;
    is_input_const.emplace_back(false);
    is_input_const.emplace_back(true);
    op_desc_ptr->SetIsInputConst(is_input_const);

    shared_ptr<ge::GeTensorDesc> output_desc_ptr = make_shared<ge::GeTensorDesc>();
    output_desc_ptr->SetDataType(set_dtype);
    output_desc_ptr->SetShape(shape_desc);
    op_desc_ptr->AddOutputDesc("z", output_desc_ptr->Clone());

    AttrUtils::SetInt(op_desc_ptr, "imply_type", EN_IMPL_HW_TBE);
    NodePtr conv_node = graph->AddNode(op_desc_ptr);
    op_desc_ptr->SetName("conv2");
    NodePtr conv_next_node = graph->AddNode(op_desc_ptr);
    GraphUtils::AddEdge(conv_node->GetOutDataAnchor(0), conv_next_node->GetInDataAnchor(0));
  }

  static ComputeGraphPtr BuildGraph(vector<Operator> inputs, string graph_name) {
    Graph graph(graph_name);
    vector<Operator> outputs{};
    graph.SetInputs(inputs).SetOutputs(outputs);
    return GraphUtils::GetComputeGraph(graph);
  }
  /*
        data1 data2         data3 data4
           \  /               /\  /
           conv             /   add
            |             /      |
      /   /   \  \      /        |
    mean neg SSDDetectionOutput PReLU
    (out1) \    /    \           |
            \  /       \       split
             sub         \     /  \
               \           mul   pooling
                 \        /  \   (out4)
                   \    /     \
                  FloorDiv activation
                   (out2)    (out3)
   */
/*    static ComputeGraphPtr GenGraphTest1()
    {
        auto data1 = op::Data();
        auto data2 = op::Data();
        auto data3 = op::Data();
        auto data4 = op::Data();
        auto conv = op::Conv2D().set_input_x(data1).set_input_filter(data2);
        auto add = op::Add().set_input_x1(data3).set_input_x2(data4);
        auto mean = op::Mean().set_input_x(conv);
        auto neg = op::Neg().set_input_x(conv);
        auto detect_out = op::SSDDetectionOutput().set_input_x1(conv).set_input_x2(conv).set_input_x3(data3);
        auto prelu = op::PReLU().set_input_x(add);
        auto sub = op::Sub().set_input_x1(neg).set_input_x2(detect_out, "y1");
        auto split = op::SplitD().set_input_input_value(prelu).create_dynamic_output_output_data(2).set_attr_split_dim(0).set_attr_num_split(1);
        auto mul = op::Mul().set_input_x(detect_out, "y2").set_input_y(split, "output_data0");
        auto pool = op::Pooling().set_input_x(split, "output_data1");
        auto div = op::FloorDiv().set_input_x(sub).set_input_y(mul);
        auto activation = op::Activation().set_input_x(mul);

        return BuildGraph({data1, data2, data3, data4}, "graph_test1");
    }
*/
  static ComputeGraphPtr GenGraphBiasAdd() {
    auto data1_feature = op::Data();
    auto data2_weight = op::Data();
    auto data3_bias = op::Data();

    auto matmul = op::MatMul().set_input_x1(data1_feature).set_input_x2(data2_weight);
    auto biasadd = op::BiasAdd().set_input_bias(data3_bias).set_input_x(matmul);

    auto y = op::Data().set_input_x(biasadd);

    return BuildGraph({data1_feature, data2_weight, data3_bias}, "graph_biasadd");
  }

  static ComputeGraphPtr SquareSumV1() {
    auto data1 = op::Data("Input0");
    auto square0 = op::Square("Square0").set_input_x(data1);
    auto sum0 = op::ReduceSum("Sum0").set_input_x(square0);
    auto data2 = op::Data("DataOut0").set_input_x(sum0);
    ComputeGraphPtr tmp_graph = BuildGraph({data1}, "graph_SquareSumV1");
    ge::NodePtr sq = tmp_graph->FindNode("Square0");
    string stream_label = "All_Cast_t";
    ge::AttrUtils::SetStr(sq->GetOpDesc(), "_stream_label", stream_label);
    return tmp_graph;
  }

  static ComputeGraphPtr GenGraphSoftGrad() {
    auto data1_grad_softmax = op::Data();
    auto data2_softmax = op::Data();

    auto mul1 = op::Mul().set_input_x1(data1_grad_softmax).set_input_x2(data2_softmax);
    auto sum0 = op::ReduceSum().set_input_x(mul1);
    auto mul2 = op::Mul().set_input_x1(sum0).set_input_x2(data2_softmax);

    auto grad_x = op::Data().set_input_x(mul2);

    return BuildGraph({data1_grad_softmax, data2_softmax}, "graph_softmaxgrad");
  }

  static void CreateTwoOpDescGraph(ComputeGraphPtr graph) {
    OpDescPtr bn_op = std::make_shared<OpDesc>("batchnormal", "BatchNorm");
    OpDescPtr relu_op = std::make_shared<OpDesc>("relu", "Activation");
    OpDescPtr max_op = std::make_shared<OpDesc>("max", "Maximum");

    // add descriptor
    vector<int64_t> dims = {1, 2, 3, 4};
    GeShape shape(dims);

    GeTensorDesc in_desc1(shape);
    in_desc1.SetFormat(FORMAT_NCHW);
    in_desc1.SetDataType(DT_FLOAT16);
    relu_op->AddInputDesc("x", in_desc1);

    GeTensorDesc out_desc1(shape);
    out_desc1.SetFormat(FORMAT_HWCN);
    out_desc1.SetDataType(DT_FLOAT16);
    relu_op->AddOutputDesc("y", out_desc1);

    GeTensorDesc in_desc2(shape);
    in_desc2.SetFormat(FORMAT_FRACTAL_Z);
    in_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddInputDesc("x", in_desc2);

    GeTensorDesc out_desc2(shape);
    out_desc2.SetFormat(FORMAT_NHWC);
    out_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddOutputDesc("y", out_desc2);
    std::vector<bool> is_in_const_vec = {false};
    bn_op->SetIsInputConst(is_in_const_vec);

    GeTensorDesc in_desc3(shape);
    in_desc3.SetFormat(FORMAT_FRACTAL_Z);
    in_desc3.SetDataType(DT_FLOAT16);
    max_op->AddInputDesc("x", in_desc3);

    GeTensorDesc in_desc4(shape);
    in_desc4.SetFormat(FORMAT_FRACTAL_Z);
    in_desc4.SetDataType(DT_FLOAT16);
    max_op->AddInputDesc("y", in_desc4);

    GeTensorDesc out_desc3(shape);
    out_desc3.SetFormat(FORMAT_NHWC);
    out_desc3.SetDataType(DT_FLOAT16);
    max_op->AddOutputDesc("z", out_desc3);
    std::vector<bool> is_input_const_vec = {false, true};
    max_op->SetIsInputConst(is_input_const_vec);


    ge::AttrUtils::SetInt(bn_op, FE_IMPLY_TYPE, static_cast<int>(EN_IMPL_HW_TBE));
    ge::AttrUtils::SetInt(relu_op, FE_IMPLY_TYPE, static_cast<int>(EN_IMPL_HW_GENERAL_CCE));
    ge::AttrUtils::SetInt(max_op, FE_IMPLY_TYPE, static_cast<int>(EN_IMPL_HW_GENERAL_CCE));

    NodePtr bn_node = graph->AddNode(bn_op);
    NodePtr relu_node = graph->AddNode(relu_op);
    NodePtr max_node = graph->AddNode(max_op);
    GraphUtils::AddEdge(bn_node->GetOutDataAnchor(0), relu_node->GetInDataAnchor(0));
    GraphUtils::AddEdge(relu_node->GetOutDataAnchor(0), max_node->GetInDataAnchor(0));
  }

  static void CreateConcatOpDescGraph(ComputeGraphPtr graph) {
    OpDescPtr bn_op = std::make_shared<OpDesc>("batchnormal", "BatchNorm");
    OpDescPtr shape_op = std::make_shared<OpDesc>("shape", "Shape");
    OpDescPtr concat_op = std::make_shared<OpDesc>("concat", "ConcatD");
    OpDescPtr relu_op = std::make_shared<OpDesc>("relu", "Relu");
    // add descriptor
    vector<int64_t> dims = {1, 2, 3, 32};
    GeShape shape(dims);

    GeTensorDesc in_desc1(shape);
    in_desc1.SetFormat(FORMAT_NCHW);
    in_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("x", in_desc1);

    GeTensorDesc in_desc11(shape);
    in_desc11.SetFormat(FORMAT_NCHW);
    in_desc11.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("z", in_desc11);

    GeTensorDesc out_desc1(shape);
    out_desc1.SetFormat(FORMAT_HWCN);
    out_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddOutputDesc("y", out_desc1);

    GeTensorDesc in_desc2(shape);
    in_desc2.SetFormat(FORMAT_FRACTAL_Z);
    in_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddInputDesc("x", in_desc2);

    GeTensorDesc out_desc2(shape);
    out_desc2.SetFormat(FORMAT_NHWC);
    out_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddOutputDesc("y", out_desc2);

    GeTensorDesc in_desc3(shape);
    in_desc3.SetFormat(FORMAT_NCHW);
    in_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddInputDesc("x", in_desc3);

    GeTensorDesc out_desc3(shape);
    out_desc3.SetFormat(FORMAT_HWCN);
    out_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddOutputDesc("y", out_desc3);

    GeTensorDesc in_desc4(shape);
    in_desc4.SetFormat(FORMAT_NCHW);
    in_desc4.SetDataType(DT_FLOAT16);
    relu_op->AddInputDesc("x", in_desc4);

    GeTensorDesc out_desc4(shape);
    out_desc4.SetFormat(FORMAT_HWCN);
    out_desc4.SetDataType(DT_FLOAT16);
    relu_op->AddOutputDesc("y", out_desc4);

    std::vector<bool> is_in_const_vec = {false};
    bn_op->SetIsInputConst(is_in_const_vec);

    ge::AttrUtils::SetInt(bn_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_TBE));
    ge::AttrUtils::SetInt(concat_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_GENERAL_CCE));
    (void) ge::AttrUtils::SetInt(concat_op, CONCAT_DIM, 0);
    NodePtr bn_node = graph->AddNode(bn_op);
    NodePtr concat_node = graph->AddNode(concat_op);
    NodePtr shape_node = graph->AddNode(shape_op);
    NodePtr relu_node = graph->AddNode(relu_op);

    GraphUtils::AddEdge(bn_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(0));
    GraphUtils::AddEdge(shape_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(1));
    GraphUtils::AddEdge(concat_node->GetOutDataAnchor(0),
                        relu_node->GetInDataAnchor(0));
  }

  static void CreateConcatOpDescGraph2(ComputeGraphPtr graph) {
    OpDescPtr placeholder_op =
            std::make_shared<OpDesc>("placeholder", "PlaceHolder");
    OpDescPtr shape_op = std::make_shared<OpDesc>("shape", "Shape");
    OpDescPtr concat_op = std::make_shared<OpDesc>("concat", "ConcatD");

    // add descriptor
    vector<int64_t> dims = {1, 2, 3, 32};
    GeShape shape(dims);

    GeTensorDesc in_desc1(shape);
    in_desc1.SetFormat(FORMAT_NCHW);
    in_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("x", in_desc1);

    GeTensorDesc in_desc11(shape);
    in_desc11.SetFormat(FORMAT_NCHW);
    in_desc11.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("z", in_desc11);

    GeTensorDesc out_desc1(shape);
    out_desc1.SetFormat(FORMAT_HWCN);
    out_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddOutputDesc("y", out_desc1);

    GeTensorDesc in_desc2(shape);
    in_desc2.SetFormat(FORMAT_FRACTAL_Z);
    in_desc2.SetDataType(DT_FLOAT16);
    placeholder_op->AddInputDesc("x", in_desc2);

    GeTensorDesc out_desc2(shape);
    out_desc2.SetFormat(FORMAT_NHWC);
    out_desc2.SetDataType(DT_FLOAT16);
    placeholder_op->AddOutputDesc("y", out_desc2);

    GeTensorDesc in_desc3(shape);
    in_desc3.SetFormat(FORMAT_NCHW);
    in_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddInputDesc("x", in_desc3);

    GeTensorDesc out_desc3(shape);
    out_desc3.SetFormat(FORMAT_HWCN);
    out_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddOutputDesc("y", out_desc3);

    std::vector<bool> is_in_const_vec = {false};
    placeholder_op->SetIsInputConst(is_in_const_vec);

    ge::AttrUtils::SetInt(placeholder_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_TBE));
    ge::AttrUtils::SetInt(concat_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_GENERAL_CCE));
    (void) ge::AttrUtils::SetInt(concat_op, CONCAT_DIM, 0);
    NodePtr placeholder_node = graph->AddNode(placeholder_op);
    NodePtr concat_node = graph->AddNode(concat_op);
    NodePtr shape_node = graph->AddNode(shape_op);
    GraphUtils::AddEdge(placeholder_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(0));
    GraphUtils::AddEdge(shape_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(1));
  }

  static void CreateConcatOpDescGraph3(ComputeGraphPtr graph) {
    OpDescPtr bn_op = std::make_shared<OpDesc>("batchnormal", "BatchNorm");
    OpDescPtr shape_op = std::make_shared<OpDesc>("shape", "Shape");
    OpDescPtr concat_op = std::make_shared<OpDesc>("concat", "ConcatD");

    // add descriptor
    vector<int64_t> dims = {1, 2, 3, 32};
    GeShape shape(dims);

    GeTensorDesc in_desc1(shape);
    in_desc1.SetFormat(FORMAT_NCHW);
    in_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("x", in_desc1);

    GeTensorDesc in_desc11(shape);
    in_desc11.SetFormat(FORMAT_NCHW);
    in_desc11.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("z", in_desc11);

    GeTensorDesc out_desc1(shape);
    out_desc1.SetFormat(FORMAT_HWCN);
    out_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddOutputDesc("y", out_desc1);

    GeTensorDesc in_desc2(shape);
    in_desc2.SetFormat(FORMAT_FRACTAL_Z);
    in_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddInputDesc("x", in_desc2);

    GeTensorDesc out_desc2(shape);
    out_desc2.SetFormat(FORMAT_NHWC);
    out_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddOutputDesc("y", out_desc2);

    GeTensorDesc in_desc3(shape);
    in_desc3.SetFormat(FORMAT_NCHW);
    in_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddInputDesc("x", in_desc3);

    GeTensorDesc out_desc3(shape);
    out_desc3.SetFormat(FORMAT_HWCN);
    out_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddOutputDesc("y", out_desc3);

    std::vector<bool> is_in_const_vec = {false};
    bn_op->SetIsInputConst(is_in_const_vec);

    ge::AttrUtils::SetInt(bn_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_TBE));
    ge::AttrUtils::SetInt(concat_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_GENERAL_CCE));
    (void) ge::AttrUtils::SetInt(concat_op, CONCAT_DIM, 0);
    ge::AttrUtils::SetBool(bn_op, ge::ATTR_NAME_CONTINUOUS_INPUT, true);
    NodePtr bn_node = graph->AddNode(bn_op);
    NodePtr concat_node = graph->AddNode(concat_op);
    NodePtr shape_node = graph->AddNode(shape_op);
    GraphUtils::AddEdge(bn_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(0));
    GraphUtils::AddEdge(shape_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(1));
  }

  static void CreateConcatOpDescGraph4(ComputeGraphPtr graph) {
    OpDescPtr bn_op = std::make_shared<OpDesc>("batchnormal", "BatchNorm");
    OpDescPtr shape_op = std::make_shared<OpDesc>("shape", "Shape");
    OpDescPtr concat_op = std::make_shared<OpDesc>("concat", "ConcatD");

    // add descriptor
    vector<int64_t> dims = {1, 2, 3, 32};
    GeShape shape(dims);

    GeTensorDesc in_desc1(shape);
    in_desc1.SetFormat(FORMAT_NCHW);
    in_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("x", in_desc1);

    GeTensorDesc in_desc11(shape);
    in_desc11.SetFormat(FORMAT_NCHW);
    in_desc11.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("z", in_desc11);

    GeTensorDesc out_desc1(shape);
    out_desc1.SetFormat(FORMAT_HWCN);
    out_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddOutputDesc("y", out_desc1);

    GeTensorDesc in_desc2(shape);
    in_desc2.SetFormat(FORMAT_FRACTAL_Z);
    in_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddInputDesc("x", in_desc2);

    GeTensorDesc out_desc2(shape);
    out_desc2.SetFormat(FORMAT_NHWC);
    out_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddOutputDesc("y", out_desc2);

    GeTensorDesc in_desc3(shape);
    in_desc3.SetFormat(FORMAT_NCHW);
    in_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddInputDesc("x", in_desc3);

    GeTensorDesc out_desc3(shape);
    out_desc3.SetFormat(FORMAT_HWCN);
    out_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddOutputDesc("y", out_desc3);

    std::vector<bool> is_in_const_vec = {false};
    bn_op->SetIsInputConst(is_in_const_vec);

    ge::AttrUtils::SetInt(bn_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_TBE));
    ge::AttrUtils::SetInt(concat_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_GENERAL_CCE));
    (void) ge::AttrUtils::SetInt(concat_op, CONCAT_DIM, 0);
    ge::AttrUtils::SetBool(bn_op, ge::ATTR_NAME_CONTINUOUS_OUTPUT, true);
    NodePtr bn_node = graph->AddNode(bn_op);
    NodePtr concat_node = graph->AddNode(concat_op);
    NodePtr shape_node = graph->AddNode(shape_op);
    GraphUtils::AddEdge(bn_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(0));
    GraphUtils::AddEdge(shape_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(1));
  }

  static void CreateConcatOpDescGraph5(ComputeGraphPtr graph) {
    OpDescPtr bn_op = std::make_shared<OpDesc>("batchnormal", "BatchNorm");
    OpDescPtr shape_op = std::make_shared<OpDesc>("shape", "Shape");
    OpDescPtr concat_op = std::make_shared<OpDesc>("concat", "ConcatD");

    // add descriptor
    vector<int64_t> dims = {1, 2, 3, 32};
    GeShape shape(dims);

    GeTensorDesc in_desc1(shape);
    in_desc1.SetFormat(FORMAT_NCHW);
    in_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("x", in_desc1);

    GeTensorDesc in_desc11(shape);
    in_desc11.SetFormat(FORMAT_NCHW);
    in_desc11.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("z", in_desc11);

    GeTensorDesc out_desc1(shape);
    out_desc1.SetFormat(FORMAT_HWCN);
    out_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddOutputDesc("y", out_desc1);

    GeTensorDesc in_desc2(shape);
    in_desc2.SetFormat(FORMAT_FRACTAL_Z);
    in_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddInputDesc("x", in_desc2);

    GeTensorDesc out_desc2(shape);
    out_desc2.SetFormat(FORMAT_NHWC);
    out_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddOutputDesc("y", out_desc2);

    GeTensorDesc in_desc3(shape);
    in_desc3.SetFormat(FORMAT_NCHW);
    in_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddInputDesc("x", in_desc3);

    GeTensorDesc out_desc3(shape);
    out_desc3.SetFormat(FORMAT_HWCN);
    out_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddOutputDesc("y", out_desc3);

    std::vector<bool> is_in_const_vec = {false};
    bn_op->SetIsInputConst(is_in_const_vec);

    ge::AttrUtils::SetInt(bn_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_TBE));
    ge::AttrUtils::SetInt(concat_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_GENERAL_CCE));
    (void) ge::AttrUtils::SetInt(concat_op, CONCAT_DIM, 0);
    ge::AttrUtils::SetBool(bn_op, ge::ATTR_NAME_REFERENCE, true);
    NodePtr bn_node = graph->AddNode(bn_op);
    NodePtr concat_node = graph->AddNode(concat_op);
    NodePtr shape_node = graph->AddNode(shape_op);
    GraphUtils::AddEdge(bn_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(0));
    GraphUtils::AddEdge(shape_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(1));
  }

  static void CreateConcatOpDescGraph6(ComputeGraphPtr graph) {
    OpDescPtr bn_op = std::make_shared<OpDesc>("batchnormal", "BatchNorm");
    OpDescPtr shape_op = std::make_shared<OpDesc>("shape", "Shape");
    OpDescPtr concat_op = std::make_shared<OpDesc>("concat", "ConcatD");
    OpDescPtr relu_op = std::make_shared<OpDesc>("relu", "Relu");

    // add descriptor
    vector<int64_t> dims = {1, 2, 3, 32};
    GeShape shape(dims);

    GeTensorDesc in_desc1(shape);
    in_desc1.SetFormat(FORMAT_NCHW);
    in_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("x", in_desc1);

    GeTensorDesc in_desc11(shape);
    in_desc11.SetFormat(FORMAT_NCHW);
    in_desc11.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("z", in_desc11);

    GeTensorDesc out_desc1(shape);
    out_desc1.SetFormat(FORMAT_HWCN);
    out_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddOutputDesc("y", out_desc1);

    GeTensorDesc in_desc2(shape);
    in_desc2.SetFormat(FORMAT_FRACTAL_Z);
    in_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddInputDesc("x", in_desc2);

    GeTensorDesc out_desc2(shape);
    out_desc2.SetFormat(FORMAT_NHWC);
    out_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddOutputDesc("y", out_desc2);

    GeTensorDesc in_desc3(shape);
    in_desc3.SetFormat(FORMAT_NCHW);
    in_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddInputDesc("x", in_desc3);

    GeTensorDesc out_desc3(shape);
    out_desc3.SetFormat(FORMAT_HWCN);
    out_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddOutputDesc("y", out_desc3);

    GeTensorDesc in_desc4(shape);
    in_desc4.SetFormat(FORMAT_NCHW);
    in_desc4.SetDataType(DT_FLOAT16);
    relu_op->AddInputDesc("x", in_desc4);

    GeTensorDesc out_desc4(shape);
    out_desc4.SetFormat(FORMAT_HWCN);
    out_desc4.SetDataType(DT_FLOAT16);
    relu_op->AddOutputDesc("y", out_desc4);

    std::vector<bool> is_in_const_vec = {false};
    bn_op->SetIsInputConst(is_in_const_vec);

    ge::AttrUtils::SetInt(bn_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_TBE));
    ge::AttrUtils::SetInt(concat_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_GENERAL_CCE));
    (void) ge::AttrUtils::SetInt(concat_op, CONCAT_DIM, 0);
    ge::AttrUtils::SetBool(bn_op, ge::ATTR_NAME_NOTASK, true);
    NodePtr bn_node = graph->AddNode(bn_op);
    NodePtr concat_node = graph->AddNode(concat_op);
    NodePtr shape_node = graph->AddNode(shape_op);
    NodePtr relu_node = graph->AddNode(relu_op);
    GraphUtils::AddEdge(bn_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(0));
    GraphUtils::AddEdge(shape_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(1));
    GraphUtils::AddEdge(concat_node->GetOutDataAnchor(0),
                        relu_node->GetInDataAnchor(0));
  }

  static void CreateConcatOpDescGraph7(ComputeGraphPtr graph) {
    OpDescPtr bn_op = std::make_shared<OpDesc>("batchnormal", "BatchNorm");
    OpDescPtr concat_op = std::make_shared<OpDesc>("concat", "ConcatD");
    OpDescPtr relu_op = std::make_shared<OpDesc>("relu", "Relu");
    // add descriptor
    vector<int64_t> dims = {1, 2, 3, 32};
    GeShape shape(dims);

    GeTensorDesc in_desc1(shape);
    in_desc1.SetFormat(FORMAT_NCHW);
    in_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("x", in_desc1);

    GeTensorDesc out_desc1(shape);
    out_desc1.SetFormat(FORMAT_HWCN);
    out_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddOutputDesc("y", out_desc1);

    GeTensorDesc in_desc2(shape);
    in_desc2.SetFormat(FORMAT_FRACTAL_Z);
    in_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddInputDesc("x", in_desc2);

    GeTensorDesc out_desc2(shape);
    out_desc2.SetFormat(FORMAT_NHWC);
    out_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddOutputDesc("y", out_desc2);
    std::vector<bool> is_in_const_vec = {false};
    bn_op->SetIsInputConst(is_in_const_vec);
    GeTensorDesc in_desc4(shape);
    in_desc4.SetFormat(FORMAT_NCHW);
    in_desc4.SetDataType(DT_FLOAT16);
    relu_op->AddInputDesc("x", in_desc4);

    GeTensorDesc out_desc4(shape);
    out_desc4.SetFormat(FORMAT_HWCN);
    out_desc4.SetDataType(DT_FLOAT16);
    relu_op->AddOutputDesc("y", out_desc4);

    ge::AttrUtils::SetInt(bn_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_TBE));
    ge::AttrUtils::SetInt(concat_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_GENERAL_CCE));
    (void) ge::AttrUtils::SetInt(concat_op, CONCAT_DIM, 0);
    NodePtr bn_node = graph->AddNode(bn_op);
    NodePtr concat_node = graph->AddNode(concat_op);
    NodePtr relu_node = graph->AddNode(relu_op);
    GraphUtils::AddEdge(bn_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(0));
    GraphUtils::AddEdge(concat_node->GetOutDataAnchor(0),
                        relu_node->GetInDataAnchor(0));
  }

  static void CreateConcatOpDescGraph8(ComputeGraphPtr graph) {
    OpDescPtr bn_op = std::make_shared<OpDesc>("batchnormal", "BatchNorm");
    OpDescPtr shape_op = std::make_shared<OpDesc>("shape", "Shape");
    OpDescPtr concat_op = std::make_shared<OpDesc>("concat", "ConcatD");

    // add descriptor
    vector<int64_t> dims = {1, 2, 3, 32};
    GeShape shape(dims);

    GeTensorDesc in_desc1(shape);
    in_desc1.SetFormat(FORMAT_NCHW);
    in_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("x", in_desc1);

    GeTensorDesc in_desc11(shape);
    in_desc11.SetFormat(FORMAT_NCHW);
    in_desc11.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("z", in_desc11);

    GeTensorDesc out_desc1(shape);
    out_desc1.SetFormat(FORMAT_HWCN);
    out_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddOutputDesc("y", out_desc1);

    GeTensorDesc in_desc2(shape);
    in_desc2.SetFormat(FORMAT_FRACTAL_Z);
    in_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddInputDesc("x", in_desc2);

    GeTensorDesc out_desc2(shape);
    out_desc2.SetFormat(FORMAT_NHWC);
    out_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddOutputDesc("y", out_desc2);

    GeTensorDesc in_desc3(shape);
    in_desc3.SetFormat(FORMAT_NCHW);
    in_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddInputDesc("x", in_desc3);

    GeTensorDesc out_desc3(shape);
    out_desc3.SetFormat(FORMAT_HWCN);
    out_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddOutputDesc("y", out_desc3);

    std::vector<bool> is_in_const_vec = {false};
    bn_op->SetIsInputConst(is_in_const_vec);

    ge::AttrUtils::SetInt(bn_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_TBE));
    ge::AttrUtils::SetInt(concat_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_GENERAL_CCE));
    (void) ge::AttrUtils::SetInt(concat_op, CONCAT_DIM, 1);
    NodePtr bn_node = graph->AddNode(bn_op);
    NodePtr concat_node = graph->AddNode(concat_op);
    NodePtr shape_node = graph->AddNode(shape_op);
    GraphUtils::AddEdge(bn_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(0));
    GraphUtils::AddEdge(shape_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(1));
  }

  static void CreateConcatOpDescGraph9(ComputeGraphPtr graph) {
    OpDescPtr bn_op = std::make_shared<OpDesc>("batchnormal", "BatchNorm");
    OpDescPtr shape_op = std::make_shared<OpDesc>("shape", "Shape");
    OpDescPtr concat_op = std::make_shared<OpDesc>("concat", "ConcatD");

    // add descriptor
    vector<int64_t> dims = {1, 2, 3, 32};
    GeShape shape(dims);

    GeTensorDesc in_desc1(shape);
    in_desc1.SetFormat(FORMAT_NCHW);
    in_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("x", in_desc1);

    GeTensorDesc in_desc11(shape);
    in_desc11.SetFormat(FORMAT_NCHW);
    in_desc11.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("z", in_desc11);

    GeTensorDesc out_desc1(shape);
    out_desc1.SetFormat(FORMAT_HWCN);
    out_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddOutputDesc("y", out_desc1);

    GeTensorDesc in_desc2(shape);
    in_desc2.SetFormat(FORMAT_FRACTAL_Z);
    in_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddInputDesc("x", in_desc2);

    GeTensorDesc out_desc2(shape);
    out_desc2.SetFormat(FORMAT_NHWC);
    out_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddOutputDesc("y", out_desc2);

    GeTensorDesc in_desc3(shape);
    in_desc3.SetFormat(FORMAT_NCHW);
    in_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddInputDesc("x", in_desc3);

    GeTensorDesc out_desc3(shape);
    out_desc3.SetFormat(FORMAT_HWCN);
    out_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddOutputDesc("y", out_desc3);

    std::vector<bool> is_in_const_vec = {false};
    bn_op->SetIsInputConst(is_in_const_vec);

    ge::AttrUtils::SetInt(bn_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_TBE));
    ge::AttrUtils::SetInt(concat_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_GENERAL_CCE));
    (void) ge::AttrUtils::SetInt(concat_op, CONCAT_DIM, 0);
    vector<int64_t> output_index;
    output_index.push_back(0);
    (void) ge::AttrUtils::SetListInt(bn_op, ge::ATOMIC_ATTR_OUTPUT_INDEX,
                                     output_index);
    NodePtr bn_node = graph->AddNode(bn_op);
    NodePtr concat_node = graph->AddNode(concat_op);
    NodePtr shape_node = graph->AddNode(shape_op);
    GraphUtils::AddEdge(bn_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(0));
    GraphUtils::AddEdge(shape_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(1));
  }

  static void CreateConcatOpDescGraph10(ComputeGraphPtr graph) {
    OpDescPtr bn_op = std::make_shared<OpDesc>("batchnormal", "BatchNorm");
    OpDescPtr concat_op = std::make_shared<OpDesc>("concat", "ConcatD");

    // add descriptor
    vector<int64_t> dims = {1, 2, 3, 32};
    GeShape shape(dims);

    GeTensorDesc in_desc1(shape);
    in_desc1.SetFormat(FORMAT_NCHW);
    in_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("x", in_desc1);

    GeTensorDesc out_desc1(shape);
    out_desc1.SetFormat(FORMAT_HWCN);
    out_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddOutputDesc("y", out_desc1);

    GeTensorDesc in_desc2(shape);
    in_desc2.SetFormat(FORMAT_FRACTAL_Z);
    in_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddInputDesc("x", in_desc2);

    GeTensorDesc out_desc2(shape);
    out_desc2.SetFormat(FORMAT_NHWC);
    out_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddOutputDesc("y", out_desc2);
    std::vector<bool> is_in_const_vec = {false};
    bn_op->SetIsInputConst(is_in_const_vec);

    ge::AttrUtils::SetInt(bn_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_TBE));
    ge::AttrUtils::SetInt(concat_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_GENERAL_CCE));
    (void) ge::AttrUtils::SetInt(concat_op, CONCAT_DIM, 0);
    ge::AttrUtils::SetBool(bn_op, ge::ATTR_NAME_NOTASK, true);
    NodePtr bn_node = graph->AddNode(bn_op);
    NodePtr concat_node = graph->AddNode(concat_op);
    GraphUtils::AddEdge(bn_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(0));
  }

  static void CreateConcatOpDescGraph11(ComputeGraphPtr graph) {
    OpDescPtr bn_op = std::make_shared<OpDesc>("batchnormal", "BatchNorm");
    OpDescPtr shape_op = std::make_shared<OpDesc>("shape", "Shape");
    OpDescPtr concat_op = std::make_shared<OpDesc>("concat", "ConcatD");

    // add descriptor
    vector<int64_t> dims = {1, 2, 3, 32};
    GeShape shape(dims);

    GeTensorDesc in_desc1(shape);
    in_desc1.SetFormat(FORMAT_NCHW);
    in_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("x", in_desc1);

    GeTensorDesc in_desc11(shape);
    in_desc11.SetFormat(FORMAT_NCHW);
    in_desc11.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("z", in_desc11);

    GeTensorDesc out_desc1(shape);
    out_desc1.SetFormat(FORMAT_HWCN);
    out_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddOutputDesc("y", out_desc1);

    GeTensorDesc in_desc2(shape);
    in_desc2.SetFormat(FORMAT_FRACTAL_Z);
    in_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddInputDesc("x", in_desc2);

    GeTensorDesc out_desc2(shape);
    out_desc2.SetFormat(FORMAT_NHWC);
    out_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddOutputDesc("y", out_desc2);

    GeTensorDesc in_desc3(shape);
    in_desc3.SetFormat(FORMAT_NCHW);
    in_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddInputDesc("x", in_desc3);

    GeTensorDesc out_desc3(shape);
    out_desc3.SetFormat(FORMAT_HWCN);
    out_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddOutputDesc("y", out_desc3);

    std::vector<bool> is_in_const_vec = {false};
    bn_op->SetIsInputConst(is_in_const_vec);

    ge::AttrUtils::SetInt(bn_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_TBE));
    ge::AttrUtils::SetInt(concat_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_GENERAL_CCE));
    (void) ge::AttrUtils::SetInt(concat_op, CONCAT_DIM, 0);
    ge::AttrUtils::SetBool(shape_op, ge::ATTR_NAME_REFERENCE, true);
    NodePtr bn_node = graph->AddNode(bn_op);
    NodePtr concat_node = graph->AddNode(concat_op);
    NodePtr shape_node = graph->AddNode(shape_op);
    GraphUtils::AddEdge(bn_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(0));
    GraphUtils::AddEdge(shape_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(1));
  }

  static void CreateConcatOpDescGraph12(ComputeGraphPtr graph) {
    OpDescPtr bn_op = std::make_shared<OpDesc>("batchnormal", "BatchNorm");
    OpDescPtr shape_op = std::make_shared<OpDesc>("shape", "Shape");
    OpDescPtr concat_op = std::make_shared<OpDesc>("concat", "ConcatD");
    OpDescPtr end_op = std::make_shared<OpDesc>("end", "End");

    // add descriptor
    vector<int64_t> dims = {1, 2, 3, 32};
    GeShape shape(dims);

    GeTensorDesc in_desc1(shape);
    in_desc1.SetFormat(FORMAT_NCHW);
    in_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("x", in_desc1);

    GeTensorDesc in_desc11(shape);
    in_desc11.SetFormat(FORMAT_NCHW);
    in_desc11.SetDataType(DT_FLOAT16);
    concat_op->AddInputDesc("z", in_desc11);

    GeTensorDesc out_desc1(shape);
    out_desc1.SetFormat(FORMAT_HWCN);
    out_desc1.SetDataType(DT_FLOAT16);
    concat_op->AddOutputDesc("y", out_desc1);

    GeTensorDesc in_desc2(shape);
    in_desc2.SetFormat(FORMAT_FRACTAL_Z);
    in_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddInputDesc("x", in_desc2);

    GeTensorDesc out_desc2(shape);
    out_desc2.SetFormat(FORMAT_NHWC);
    out_desc2.SetDataType(DT_FLOAT16);
    bn_op->AddOutputDesc("y", out_desc2);

    GeTensorDesc in_desc3(shape);
    in_desc3.SetFormat(FORMAT_NCHW);
    in_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddInputDesc("x", in_desc3);

    GeTensorDesc out_desc3(shape);
    out_desc3.SetFormat(FORMAT_HWCN);
    out_desc3.SetDataType(DT_FLOAT16);
    shape_op->AddOutputDesc("y", out_desc3);

    GeTensorDesc in_desc4(shape);
    in_desc4.SetFormat(FORMAT_NCHW);
    in_desc4.SetDataType(DT_FLOAT16);
    end_op->AddInputDesc("x", in_desc4);

    GeTensorDesc out_desc4(shape);
    out_desc4.SetFormat(FORMAT_HWCN);
    out_desc4.SetDataType(DT_FLOAT16);
    end_op->AddOutputDesc("y", out_desc4);

    std::vector<bool> is_in_const_vec = {false};
    bn_op->SetIsInputConst(is_in_const_vec);

    ge::AttrUtils::SetInt(bn_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_TBE));
    ge::AttrUtils::SetInt(concat_op, FE_IMPLY_TYPE,
                          static_cast<int>(EN_IMPL_HW_GENERAL_CCE));
    (void) ge::AttrUtils::SetInt(concat_op, CONCAT_DIM, 0);
    ge::AttrUtils::SetBool(bn_op, ge::ATTR_NAME_NOTASK, true);
    ge::AttrUtils::SetStr(end_op, "parentOpType", "NetOutput");
    NodePtr bn_node = graph->AddNode(bn_op);
    NodePtr concat_node = graph->AddNode(concat_op);
    NodePtr shape_node = graph->AddNode(shape_op);
    NodePtr end_node = graph->AddNode(end_op);
    GraphUtils::AddEdge(bn_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(0));
    GraphUtils::AddEdge(shape_node->GetOutDataAnchor(0),
                        concat_node->GetInDataAnchor(1));
    GraphUtils::AddEdge(concat_node->GetOutDataAnchor(0),
                        end_node->GetInDataAnchor(0));
  }
};

Status OptimizerConfigurationStub(Configuration *This, std::string& graph_file_path) {
    graph_file_path = "./air/test/engines/nneng/st/testcase/graph_optimizer/gen_graph.json";
    return fe::SUCCESS;
}
Status OptimizerConfigurationStubBiasAddSoftMaxGrad(Configuration *This, std::string& graph_file_path) {
    graph_file_path = "./air/test/engines/nneng/st/testcase/graph_optimizer/bias_add_softmaxgrad.json";
    return fe::SUCCESS;
}

Status OptimizerConfigurationStubSquareSumV1(Configuration *This, std::string& graph_file_path) {
  graph_file_path = "./air/test/engines/nneng/st/testcase/graph_optimizer/SquareSumOut.json";
  return fe::SUCCESS;
}
std::string GetBuiltInFusionConfigFilePathStubs() {
  std::string switch_priority_file_path = "./air/test/engines/nneng/st/stub/fe_config/fusion_config.json";

  return  switch_priority_file_path;
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, get_attributes_success)
{
    GraphOptimizerAttribute attrs;
    auto fe_graph_optimizer_ptr = std::make_shared<FEGraphOptimizer>(ops_info_store, op_store_adapter_manager_ptr_);

    Status status = fe_graph_optimizer_ptr->GetAttributes(attrs);

    EXPECT_EQ(fe::SUCCESS, status);
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, set_atomic_add_info_success)
{
    auto graph = std::make_shared<ComputeGraph>("test");
    CreateTwoOpDescGraph(graph);

    auto fe_graph_optimizer_ptr = std::make_shared<FEGraphOptimizer>(ops_info_store, op_store_adapter_manager_ptr_);
    //fe_graph_optimizer_ptr->init_flag_ = true;
    for (auto node : graph->GetDirectNode()) {
    string op_type = node->GetType();
    if (op_type == OP_TYPE_PLACE_HOLDER ||
    op_type == OP_TYPE_END) {
        continue;
    }
    ge::OpDescPtr op_desc_ptr = node->GetOpDesc();
    if (!ge::AttrUtils::HasAttr(op_desc_ptr, FE_IMPLY_TYPE)) {
        continue;
    }
    int tmp_imply_type = -1;
    ge::AttrUtils::GetInt(op_desc_ptr, FE_IMPLY_TYPE, tmp_imply_type);
    OpImplType op_impl_type = (OpImplType)tmp_imply_type;
    if (op_desc_ptr->GetName() == "batchnormal") {
        std::vector<uint32_t> tmp_output_index {1, 0, 0};
        bool output_index = ge::AttrUtils::SetListInt(op_desc_ptr, TBE_OP_ATOMIC_OUTPUT_INDEX, tmp_output_index);

        uint32_t atomic_flag = 1;
        bool atomic = ge::AttrUtils::SetInt(op_desc_ptr, TBE_OP_ATOMIC_WORKSPACE_FLAG, atomic_flag);
        EXPECT_EQ(output_index, true);
        EXPECT_EQ(atomic, true);
    }
    if (op_desc_ptr->GetName() == "relu") {
        ge::AttrUtils::SetInt(op_desc_ptr, FE_IMPLY_TYPE, EN_IMPL_HW_TBE);
        std::vector<uint32_t> tmp_output_index {1};
        bool output_index2 = ge::AttrUtils::SetListInt(op_desc_ptr, TBE_OP_ATOMIC_OUTPUT_INDEX, tmp_output_index);

        uint32_t atomic_flag = 0;
        bool atomic2 = ge::AttrUtils::SetInt(op_desc_ptr, TBE_OP_ATOMIC_WORKSPACE_FLAG, atomic_flag);
        EXPECT_EQ(output_index2, true);
        EXPECT_EQ(atomic2, true);
    }
    }
    Status status = fe_graph_optimizer_ptr->SetAtomicAddInfo(*(graph.get()));
    EXPECT_EQ(fe::SUCCESS, status);
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, set_atomic_add_info_success2)
{
    auto graph = std::make_shared<ComputeGraph>("test");
    CreateTwoOpDescGraph(graph);

    auto fe_graph_optimizer_ptr = std::make_shared<FEGraphOptimizer>(ops_info_store, op_store_adapter_manager_ptr_);
    //fe_graph_optimizer_ptr->init_flag_ = true;
    for (auto node : graph->GetDirectNode()) {
        string op_type = node->GetType();
        if (op_type == OP_TYPE_PLACE_HOLDER ||
        op_type == OP_TYPE_END) {
            continue;
        }
        ge::OpDescPtr op_desc_ptr = node->GetOpDesc();
        if (!ge::AttrUtils::HasAttr(op_desc_ptr, FE_IMPLY_TYPE)) {
        continue;
        }
        int tmp_imply_type = -1;
        ge::AttrUtils::GetInt(op_desc_ptr, FE_IMPLY_TYPE, tmp_imply_type);
        OpImplType op_impl_type = (OpImplType)tmp_imply_type;

        if (op_desc_ptr->GetName() == "batchnormal") {
            uint32_t atomic_flag = 1;
            bool atomic = ge::AttrUtils::SetInt(op_desc_ptr, TBE_OP_ATOMIC_WORKSPACE_FLAG, atomic_flag);
            EXPECT_EQ(atomic, true);
        }
        if (op_desc_ptr->GetName() == "relu") {
            ge::AttrUtils::SetInt(op_desc_ptr, FE_IMPLY_TYPE, EN_IMPL_HW_TBE);
            std::vector<uint32_t> tmp_output_index {0, 1};
            bool output_index = ge::AttrUtils::SetListInt(op_desc_ptr, TBE_OP_ATOMIC_OUTPUT_INDEX, tmp_output_index);
            EXPECT_EQ(output_index, true);
        }
    }
    Status status = fe_graph_optimizer_ptr->SetAtomicAddInfo(*(graph.get()));
    EXPECT_EQ(fe::SUCCESS, status);
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, set_fusion_virtual_op_success1) {
  auto graph = std::make_shared<ComputeGraph>("test");
  CreateConcatOpDescGraph(graph);
  Status status = concat_optimizer.SetFusionVirtualOp(*(graph.get()));
  EXPECT_EQ(fe::SUCCESS, status);
  for (auto node : graph->GetDirectNode()) {
    string op_type = node->GetType();
    if (op_type == "ConcatD") {
      bool no_task = false;
      ge::AttrUtils::GetBool(node->GetOpDesc(), ge::ATTR_NAME_NOTASK, no_task);
      EXPECT_EQ(no_task, false);
    }
  }
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, set_fusion_virtual_op_failed1) {
  auto graph = std::make_shared<ComputeGraph>("test");
  CreateConcatOpDescGraph2(graph);
  Status status = concat_optimizer.SetFusionVirtualOp(*(graph.get()));
  EXPECT_EQ(fe::SUCCESS, status);
  for (auto node : graph->GetDirectNode()) {
    string op_type = node->GetType();
    if (op_type == "ConcatD") {
      bool no_task = false;
      ge::AttrUtils::GetBool(node->GetOpDesc(), ge::ATTR_NAME_NOTASK, no_task);
      EXPECT_EQ(no_task, false);
    }
  }
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, set_fusion_virtual_op_failed2) {
  auto graph = std::make_shared<ComputeGraph>("test");
  CreateConcatOpDescGraph3(graph);
  Status status = concat_optimizer.SetFusionVirtualOp(*(graph.get()));
  EXPECT_EQ(fe::SUCCESS, status);
  for (auto node : graph->GetDirectNode()) {
    string op_type = node->GetType();
    if (op_type == "ConcatD") {
      bool no_task = false;
      ge::AttrUtils::GetBool(node->GetOpDesc(), ge::ATTR_NAME_NOTASK, no_task);
      EXPECT_EQ(no_task, false);
    }
  }
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, set_fusion_virtual_op_failed3) {
  auto graph = std::make_shared<ComputeGraph>("test");
  CreateConcatOpDescGraph4(graph);
  Status status = concat_optimizer.SetFusionVirtualOp(*(graph.get()));
  EXPECT_EQ(fe::SUCCESS, status);
  for (auto node : graph->GetDirectNode()) {
    string op_type = node->GetType();
    if (op_type == "ConcatD") {
      bool no_task = false;
      ge::AttrUtils::GetBool(node->GetOpDesc(), ge::ATTR_NAME_NOTASK, no_task);
      EXPECT_EQ(no_task, false);
    }
  }
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, set_fusion_virtual_op_failed4) {
  auto graph = std::make_shared<ComputeGraph>("test");
  CreateConcatOpDescGraph5(graph);
  Status status = concat_optimizer.SetFusionVirtualOp(*(graph.get()));
  EXPECT_EQ(fe::SUCCESS, status);
  for (auto node : graph->GetDirectNode()) {
    string op_type = node->GetType();
    if (op_type == "ConcatD") {
      bool no_task = false;
      ge::AttrUtils::GetBool(node->GetOpDesc(), ge::ATTR_NAME_NOTASK, no_task);
      EXPECT_EQ(no_task, false);
    }
  }
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, set_fusion_virtual_op_failed5) {
  auto graph = std::make_shared<ComputeGraph>("test");
  CreateConcatOpDescGraph6(graph);
  Status status = concat_optimizer.SetFusionVirtualOp(*(graph.get()));
  EXPECT_EQ(fe::SUCCESS, status);
  for (auto node : graph->GetDirectNode()) {
    string op_type = node->GetType();
    if (op_type == "ConcatD") {
      bool no_task = false;
      ge::AttrUtils::GetBool(node->GetOpDesc(), ge::ATTR_NAME_NOTASK, no_task);
      EXPECT_EQ(no_task, false);
    }
  }
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, set_fusion_virtual_op_success6) {
  auto graph = std::make_shared<ComputeGraph>("test");
  CreateConcatOpDescGraph7(graph);
  Status status = concat_optimizer.SetFusionVirtualOp(*(graph.get()));
  EXPECT_EQ(fe::SUCCESS, status);
  for (auto node : graph->GetDirectNode()) {
    string op_type = node->GetType();
    if (op_type == "ConcatD") {
      bool no_task = false;
      ge::AttrUtils::GetBool(node->GetOpDesc(), ge::ATTR_NAME_NOTASK, no_task);
      EXPECT_EQ(no_task, true);
    }
  }
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, set_fusion_virtual_op_failed7) {
  auto graph = std::make_shared<ComputeGraph>("test");
  CreateConcatOpDescGraph8(graph);
  Status status = concat_optimizer.SetFusionVirtualOp(*(graph.get()));
  EXPECT_EQ(fe::SUCCESS, status);
  for (auto node : graph->GetDirectNode()) {
    string op_type = node->GetType();
    if (op_type == "ConcatD") {
      bool no_task = false;
      ge::AttrUtils::GetBool(node->GetOpDesc(), ge::ATTR_NAME_NOTASK, no_task);
      EXPECT_EQ(no_task, false);
    }
  }
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, set_fusion_virtual_op_failed8) {
  auto graph = std::make_shared<ComputeGraph>("test");
  CreateConcatOpDescGraph9(graph);
  Status status = concat_optimizer.SetFusionVirtualOp(*(graph.get()));
  EXPECT_EQ(fe::SUCCESS, status);
  for (auto node : graph->GetDirectNode()) {
    string op_type = node->GetType();
    if (op_type == "ConcatD") {
      bool no_task = false;
      ge::AttrUtils::GetBool(node->GetOpDesc(), ge::ATTR_NAME_NOTASK, no_task);
      EXPECT_EQ(no_task, false);
    }
  }
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, set_fusion_virtual_op_success9) {
  auto graph = std::make_shared<ComputeGraph>("test");
  CreateConcatOpDescGraph10(graph);
  Status status = concat_optimizer.SetFusionVirtualOp(*(graph.get()));
  EXPECT_EQ(fe::SUCCESS, status);
  for (auto node : graph->GetDirectNode()) {
    string op_type = node->GetType();
    if (op_type == "ConcatD") {
      bool no_task = false;
      ge::AttrUtils::GetBool(node->GetOpDesc(), ge::ATTR_NAME_NOTASK, no_task);
      EXPECT_EQ(no_task, false);
    }
  }
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, set_fusion_virtual_op_failed10) {
  auto graph = std::make_shared<ComputeGraph>("test");
  CreateConcatOpDescGraph11(graph);
  Status status = concat_optimizer.SetFusionVirtualOp(*(graph.get()));
  EXPECT_EQ(fe::SUCCESS, status);
  for (auto node : graph->GetDirectNode()) {
    string op_type = node->GetType();
    if (op_type == "ConcatD") {
      bool no_task = false;
      ge::AttrUtils::GetBool(node->GetOpDesc(), ge::ATTR_NAME_NOTASK, no_task);
      EXPECT_EQ(no_task, false);
    }
  }
}

TEST_F(STEST_fusion_engine_fe_graph_optimizer, set_fusion_virtual_op_failed11) {
  auto graph = std::make_shared<ComputeGraph>("test");
  CreateConcatOpDescGraph12(graph);
  Status status = concat_optimizer.SetFusionVirtualOp(*(graph.get()));
  EXPECT_EQ(fe::SUCCESS, status);
  for (auto node : graph->GetDirectNode()) {
    string op_type = node->GetType();
    if (op_type == "ConcatD") {
      bool no_task = false;
      ge::AttrUtils::GetBool(node->GetOpDesc(), ge::ATTR_NAME_NOTASK, no_task);
      EXPECT_EQ(no_task, false);
    }
  }
}
